
import { fromLonLat } from 'ol/proj'
import Draw from 'ol/interaction/Draw.js';
import Overlay from 'ol/Overlay.js';
import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style.js';
import { LineString, Point, Polygon } from 'ol/geom.js';
import { OSM, Vector as VectorSource, ImageWMS } from 'ol/source.js';
import { Heatmap, Tile as TileLayer, Vector as VectorLayer, Image as ImageLayer } from 'ol/layer.js';
import { getArea, getLength } from 'ol/sphere.js';
import { unByKey } from 'ol/Observable.js';
import { Feature } from 'ol';



import store from '@/store';

export default class MapTools {
    // 地图工具类
    constructor(map) {
        this.map = map;
        this.center = [104, 36];
        this.draw = null
        this.helpTooltipElement = null
        this.measureTooltipElement = null
        this.MAX_POINTS = 500

        this.highlight = null

        //实现高亮显示
        // this.featureOverlay = new VectorLayer({
        //     source: new VectorSource(),
        //     map: map,
        //     style: new Style({
        //         image: new CircleStyle({
        //             radius: 5,
        //             fill: null,
        //             stroke: new Stroke({ color: 'red', width: 1 })
        //         })
        //     })
        // }
        // )
    }

    // 返回原视角
    resetView() {
        if (!this.map) return;
        this.map.getView().animate({
            // 只设置需要的属性即可
            center: fromLonLat(this.center), // 中心点
            zoom: 4.5, // 缩放级别
            rotation: undefined, // 缩放完成view视图旋转弧度
            duration: 1000, // 缩放持续时间，默认不需要设置
        });
    }

    // set view
    /**
     * 
     * @param {import('ol/coordinate.js').Coordinate} center 
     * @param {Number} zoom 
     * @returns 
     */
    setView(center, zoom) {
        if (!this.map) return;
        this.map.getView().animate({
            // 只设置需要的属性即可
            center: center, // 中心点
            zoom: zoom, // 缩放级别
            rotation: undefined, // 缩放完成view视图旋转弧度
            duration: 1000, // 缩放持续时间，默认不需要设置
        });
    }

    /**
     * 测距
     * @returns 
     */
    measureDistance(value) {
        if (!this.map) return;
        if (this.draw) {
            this.map.removeInteraction(this.draw);
            this.draw = null;
            this.helpTooltipElement.parentNode.removeChild(this.helpTooltipElement);
        };

        const source = new VectorSource();

        let t = value == 'area' ? "测面" : "测距";
        const vector = new VectorLayer({
            source: source,
            zIndex: 999,
            title: t + "_" + new Date().getTime(),
            name: "draw feacture",
            type: value == 'area' ? 'Polygon' : 'LineString',
            style: {
                'fill-color': 'rgba(255, 255, 255, 0.2)',
                'stroke-color': '#ffcc33',
                'stroke-width': 2,
                'circle-radius': 7,
                'circle-fill-color': '#ffcc33',
            },
        });

        this.map.addLayer(vector);

        /**
         * Currently drawn feature.
         * @type {import("../src/ol/Feature.js").default}
         */
        let sketch;

        /**
         * The help tooltip element.
         * @type {HTMLElement}
         */
        let helpTooltipElement;

        /**
         * Overlay to show the help messages.
         * @type {Overlay}
         */
        let helpTooltip;

        /**
         * The measure tooltip element.
         * @type {HTMLElement}
         */
        let measureTooltipElement;

        /**
         * Overlay to show the measurement.
         * @type {Overlay}
         */
        let measureTooltip;

        /**
         * Message to show when the user is drawing a polygon.
         * @type {string}
         */
        const continuePolygonMsg = '单击以继续绘制多边形';

        /**
         * Message to show when the user is drawing a line.
         * @type {string}
         */
        const continueLineMsg = '单击以继续绘制线条';

        /**
         * Handle pointer move.
         * @param {import("../src/ol/MapBrowserEvent").default} evt The event.
         */
        const pointerMoveHandler = function (evt) {
            if (evt.dragging) {
                return;
            }
            /** @type {string} */
            let helpMsg = '点击开始绘图';

            if (sketch) {
                const geom = sketch.getGeometry();
                if (geom instanceof Polygon) {
                    helpMsg = continuePolygonMsg;
                } else if (geom instanceof LineString) {
                    helpMsg = continueLineMsg;
                }
            }

            helpTooltipElement.innerHTML = helpMsg;
            helpTooltip.setPosition(evt.coordinate);

            helpTooltipElement.classList.remove('hidden');
        };



        this.map.on('pointermove', pointerMoveHandler);

        this.map.getViewport().addEventListener('mouseout', function () {
            helpTooltipElement.classList.add('hidden');
        });

        const typeSelect = value;

        let draw; // global so we can remove it later

        /**
         * 格式化长度输出
         * @param {LineString} line The line.
         * @return {string} The formatted length.
         */
        const formatLength = function (line) {
            const length = getLength(line);
            let output;
            if (length > 100) {
                output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km';
            } else {
                output = Math.round(length * 100) / 100 + ' ' + 'm';
            }
            return output;
        };

        /**
         * Format area output.
         * @param {Polygon} polygon The polygon.
         * @return {string} Formatted area.
         */
        const formatArea = function (polygon) {
            const area = getArea(polygon);
            let output;
            if (area > 10000) {
                output = Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>';
            } else {
                output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>';
            }
            return output;
        };
        let _this = this;
        function addInteraction() {

            const type = typeSelect == 'area' ? 'Polygon' : 'LineString';
            draw = new Draw({
                source: source,
                type: type,
                style: new Style({
                    fill: new Fill({
                        color: 'rgba(255, 255, 255, 0.2)',
                    }),
                    stroke: new Stroke({
                        color: 'rgba(0, 0, 0, 0.5)',
                        lineDash: [10, 10],
                        width: 2,
                    }),
                    image: new CircleStyle({
                        radius: 5,
                        stroke: new Stroke({
                            color: 'rgba(0, 0, 0, 0.7)',
                        }),
                        fill: new Fill({
                            color: 'rgba(255, 255, 255, 0.2)',
                        }),
                    }),
                }),
            });
            _this.map.addInteraction(draw);
            _this.draw = draw;

            createMeasureTooltip();
            createHelpTooltip();

            let listener;
            draw.on('drawstart', function (evt) {
                // set sketch
                sketch = evt.feature;

                /** @type {import("../src/ol/coordinate.js").Coordinate|undefined} */
                let tooltipCoord = evt.coordinate;

                listener = sketch.getGeometry().on('change', function (evt) {
                    const geom = evt.target;
                    let output;
                    if (geom instanceof Polygon) {
                        output = formatArea(geom);
                        tooltipCoord = geom.getInteriorPoint().getCoordinates();
                    } else if (geom instanceof LineString) {
                        output = formatLength(geom);
                        tooltipCoord = geom.getLastCoordinate();
                    }
                    measureTooltipElement.innerHTML = output;
                    measureTooltip.setPosition(tooltipCoord);
                });
            });

            draw.on('drawend', function () {
                const me = measureTooltipElement

                measureTooltipElement.className = 'ol-tooltip ol-tooltip-static'
                measureTooltip.setOffset([0, -7]);
                // unset sketch
                sketch = null;
                // unset tooltip so that a new one can be created
                measureTooltipElement = null;
                createMeasureTooltip();

                let l = {
                    title: vector.get("title"),
                    name: vector.get("name"),
                    uid: vector.ol_uid,
                    id: new Date().getTime(),
                    visible: vector.get("visible"),
                    type: vector.get("type"),
                    edit: true,
                    delete: true,
                    layer: vector,
                    children: [me],
                };
                let layeres = store.getters.getLayeres;
                layeres.ul.push(l);

                store.commit("setLayeres", layeres);
                unByKey(listener);
            });
        }

        /**
         * Creates a new help tooltip
         */
        function createHelpTooltip() {
            if (helpTooltipElement) {
                helpTooltipElement.parentNode.removeChild(helpTooltipElement);
            }
            helpTooltipElement = document.createElement('div');
            _this.helpTooltipElement = helpTooltipElement;
            helpTooltipElement.className = 'ol-tooltip hidden';
            helpTooltip = new Overlay({
                element: helpTooltipElement,
                offset: [15, 0],
                positioning: 'center-left',
            });
            _this.map.addOverlay(helpTooltip);
        }

        /**
         * Creates a new measure tooltip
         */
        function createMeasureTooltip() {
            if (measureTooltipElement) {
                measureTooltipElement.parentNode.removeChild(measureTooltipElement);
            }
            measureTooltipElement = document.createElement('div');
            _this.measureTooltipElement = measureTooltipElement;
            measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
            measureTooltip = new Overlay({
                element: measureTooltipElement,
                offset: [0, -15],
                positioning: 'bottom-center',
                stopEvent: false,
                insertFirst: false,
            });
            _this.map.addOverlay(measureTooltip);
        }


        addInteraction();
    }

    // 结束绘制
    endDraw() {
        if (!this.map) {
            throw new Error('未初始化地图');
        }
        if (!this.draw) return;

        this.map.removeInteraction(this.draw);
        this.helpTooltipElement.parentNode.removeChild(this.helpTooltipElement);
    }

    // 批量添加点
    addPoint(points) {
        if (!this.map) return;
        if (points.length === 0) return;

        const TLPL = store.state.layeres.al[1]
        let featuresArr = []

        let L_Source = TLPL.layer.getSource()
        let L_Features = TLPL.layer.getSource().getFeatures()

        let total = L_Features.length + points.length

        // 删除最前面的
        if (total > this.MAX_POINTS) {
            let overplus = total - this.MAX_POINTS
            for (let i = 0; i < overplus; i++) {
                L_Source.removeFeature(L_Features[i])
            }

        }

        points.forEach(point => {
            const feature = new Feature({
                geometry: new Point(fromLonLat([point.lon, point.lat])),
                g_id: point.id,
                g_type: "point",
            })
            featuresArr.push(feature)
        })

        TLPL.layer.getSource().addFeatures(featuresArr)

    }


    // 创建热力图
    createHeatmap(points) {
        if (!this.map) return;

        var featuresArr = []
        points.forEach(point => {
            const feature = new Feature({
                geometry: new Point(fromLonLat([point.lon, point.lat])),
            })

            featuresArr.push(feature)
        })

        var source = new VectorSource({
            features: featuresArr,
            wrapX: false
        })
        var heatMap = new Heatmap({
            source: source,//热力图资源
            isRemove: false,
            name: "openlayers 热力图",
            type: "Layer",
            opacity: 1,//透明度，默认1
            visible: true,//是否显示，默认trur
            zIndex: 995,//图层渲染的Z索引,默认按图层加载顺序叠加
            gradient: ['#00f', '#0ff', '#0f0', '#ff0', '#f00'],//热图的颜色渐变
            blur: 10,//模糊大小(像素为单位)
            radius: 4,//半径大小默认为8(像素为单位)
            // extent: [100, 30, 104, 40],//渲染范围，可选值，默认渲染全部
        })
        this.map.addLayer(heatMap)
        this.submit(heatMap)
    }


    /**
     * 创建 geoserver 热力图
     */
    createGSSHeatmap() {
        var imageLayer = new ImageLayer({
            source: new ImageWMS({
                ratio: 1,
                url: "http://localhost:8084/geoserver/ne/wms",
                crossOrigin: "anonymous", //跨域声明
                params: {
                    SERVICE: "WMS",
                    VERSION: "1.1.1",
                    REQUEST: "GetMap",
                    FORMAT: "image/png",
                    TRANSPARENT: true,
                    STYLES: null,
                    LAYERS: "ne:point1",
                    exceptions: "application/vnd.ogc.se_inimage",
                    SRS: "EPSG:4326",
                    WIDTH: 769,
                    HEIGHT: 488,
                    BBOX: "69.50390625,12.1552734375,137.0390625,54.9931640625",
                },
            }),
            isRemove: false,
            name: "geoserver 热力图",
            type: "Layer",
            zIndex: 999,
            wrapX: false,
        });

        this.map.addLayer(imageLayer);
        this.submit(imageLayer)
    }

    loadGSFaultLine() {
        var imageLayer = new ImageLayer({
            source: new ImageWMS({
                ratio: 1,
                url: "http://localhost:8084/geoserver/ne/wms",
                crossOrigin: "anonymous", //跨域声明
                params: {
                    SERVICE: "WMS",
                    VERSION: "1.1.1",
                    REQUEST: "GetMap",
                    FORMAT: "image/png",
                    TRANSPARENT: true,
                    STYLES: null,
                    LAYERS: "ne:fault_lines",
                    exceptions: "application/vnd.ogc.se_inimage",
                    SRS: "EPSG:4326",
                    WIDTH: 769,
                    HEIGHT: 488,
                    BBOX: "69.50390625,12.1552734375,137.0390625,54.9931640625",
                },
            }),
            isRemove: false,
            name: "geoserver 断层线",
            type: "Layer",
            zIndex: 999,
            wrapX: false,
        });

        this.map.addLayer(imageLayer);
        let _this = this;
        this.map.on('click', function (evt) {
            _this.displayFeatureInfo(evt.pixel);
        });


        this.submit(imageLayer)
    }

    submit(layer) {
        let l = {
            title: layer.get("name"),
            name: layer.get("name"),
            uid: layer.ol_uid,
            id: new Date().getTime(),
            visible: layer.get("visible"),
            type: layer.get("type"),
            edit: false,
            delete: true,
            layer: layer,
            children: [],
        };

        let layeres = store.getters.getLayeres;

        layeres.ul.push(l);

        store.commit("setLayeres", layeres);
    }
}

